<?php

require_once 'Pipes/Database/Sequence.php';
require_once 'Pipes/FileSystem/Model/Finders/Finder.php';
require_once 'Pipes/FileSystem/Model/Finders/Loader.php';
require_once 'Pipes/FileSystem/ModelMeta/Finder.php';
require_once 'Pipes/FileSystem/ModelMeta/Loader.php';
require_once 'Pipes/Model/Visitors/ExternalRelationshipSaver.php';
require_once 'Pipes/Model/Visitors/ExternalRelationshipRemover.php';
require_once 'Pipes/Storage.php';
require_once 'PipesImpl/Storage.php';
require_once 'PipesImpl/Model/Mapper.php';
require_once 'PipesImpl/Config.php';
require_once 'Pipes/ModelList.php';
require_once 'Pipes/Filter.php';
require_once 'Pipes/Statement/Basic.php';


class Pipes_Model_Mapper implements PipesImpl_Model_Mapper
{
	protected $_storage = null;
	protected $_config = null;
	protected $_meta = null;
	protected $_name = '';
	protected $_finderLoader = null;

	private $_finders = array();
	
	public function __construct(PipesImpl_Config $config, PipesImpl_Storage $storage) {
		$this->_storage = $storage;
		$this->_config = $config;
		
		$exploded = explode('_', get_class($this));
		$this->_name = substr(array_pop($exploded), 0, -6);
		$metaLoader = new Pipes_FileSystem_ModelMeta_Loader(
			new Pipes_FileSystem_ModelMeta_Finder($config)
		);
		$metaLoader->load($this->_name);
		$metaName = $metaLoader->lastLoaded;
		$this->_meta = new $metaName($config);

		$this->_finderLoader = new Pipes_FileSystem_Model_Finders_Loader(
			new Pipes_FileSystem_Model_Finders_Finder($config)
		);
	}
	
	public function find($criteria = null, $type = 'One') {
		if (!isset($this->_finders[$type])) {
			$this->_finderLoader->load($type);
			$finderName = $this->_finderLoader->lastLoaded;
			$this->_finders[$type] = new $finderName($this->_config, $this->_meta);
		}

		$return = $this->_finders[$type]->find($criteria);
		$return->attach(array($this, 'save'));
		return $return;
	}
	
	public function __call($method, $arguments) {
		if (substr($method, 0, 4) == 'find') {
			$type = substr($method, 4);
			return $this->find(array_shift($arguments), $type);
		}
	}
	
	public function save(PipesImpl_Model $model) {
		$model->accept(new Pipes_Model_Visitors_ExternalRelationshipSavers($this->_config));

		if ($model->isNew()) {
			$modelName = $model->getName();
			$idKey = $this->_meta->idColumn()->name;
			if (!isset($model->$idKey)) {
				$sequence = new Pipes_Database_Sequence($this->_config);
				$model->$idKey = $sequence->next();
			}
			$this->_storage->add($modelName, $model->toArray());
		} else {
			$this->_storage->modify($model->getName(), $model->toArray());
		}
	}

	public function remove(PipesImpl_Model $model) {
		$model->accept(new Pipes_Model_Visitors_ExternalRelationshipRemover($this->_config));

		$id = $model->idColumn()->name;
		$this->_storage->remove($model->getName(), $model->$id);
	}
}

